Skip to content

feat: Multi-part missions and governor profiles#1082

Draft
OH296 wants to merge 35 commits intoAdeptus-Dominus:mainfrom
OH296:random_marine_components
Draft

feat: Multi-part missions and governor profiles#1082
OH296 wants to merge 35 commits intoAdeptus-Dominus:mainfrom
OH296:random_marine_components

Conversation

@OH296
Copy link
Collaborator

@OH296 OH296 commented Dec 27, 2025

Purpose and Description

#improvements

  • add_trait now takes the arguments return_stat_diff and return_description that will return ", {(print_stat_diffs(_stat_diff))}" and "{name_role()} Has gained the trait {selec_trait.display_name}" in the order description t then stat_diff to streamline mission and immersion areas
  • New function get_imperial_navy_fleets does as says on. Tine returns An array of navy fleet ids
  • obj_en_fleets now have uids
  • New function irandom_numeral(<max_val>) tout outage midlemanand make a randomised romman numeral string of between 1and a numberofyour choosing
  • New function get_fleet_uid together a fleet by it’s uid duh
  • New Function scr_click_right mirrors scr_click_left
  • Add click right functionality to table rows in Table constructor
  • Replace hardcoded tables with Table constructor instances in unitquickFind pane
  • Systems now have permanent system_datas arrays with PlanetData instances for each planet
  • Refresh data static method added to PLanetDatas to allow instances lobe used continuously without having to reinitialise
  • Global ork planet growth reduced from 15% to 13%
  • Warbosses double growth rate to 26% when on a planet
  • OrkStrongholds reduce the roll size for work forces growth creating more growth
  • Most of enemy_ai_b folded into static methods in PlanetData
  • New static end_turn_heretics_and_corruption_growth to handle heretic stuff
  • New static end_turn_genestealer_cults to handle end turn cults stuff
  • New static end_turn_population_growth to handle imperium planet pop growth
  • New static refresh_data to refresh data from star object in PlanetData
    • Ensure tau alter population influence meter not corruption meter
    • New Mission after a particularly successful beast hunt deliver a trophy of the hunt to a regiment serving on a navy fleet
    • New Planet Feature old battle grounds, explore for a chance to find loot, once discovered you will have to beat the mechanics fleets tooter else they will pick it clean
    • New function standard_loc_data to automatically add x1,x2,y1,y2, w and h variables to constructors
    • Alerts when there are no longer any free forge worlds for navy replenishment
    • move unit name in ui manage to use a stored ReactiveString
    • Create marine Epitaphs to store cool funky nicknames a marine can pickup from doing stuff
    • create UnitGroup constructor to make finding information about an array of marines much easier
    • create SearchConditions constructor to make complex evaluations of marines easier across multiple functions and methods
    • widen use of active_roles function to reduce obj_ini.roles[100] bloat
    • add options to search by alliegence
    • re-enable chaos invasion event but make it not just trigger on the players home system
    • make chaos invasion fleets more variable and often more manageable
    • smaller chapters will get slightly better events
    • larger chapters will get slightly harder events
    • purging willow automatically reduce the highest between corruption, tau influence and cult influence
    • governors have personalities

Testing done

  • None, and I understand the risks.

Related things and/or additional context

@github-actions github-actions bot added Area: Sprites Changes to sprites/images or their under-the-hood functionality Size: Warning labels Dec 27, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 27, 2025

📝 Walkthrough

Walkthrough

A comprehensive overhaul of fleet event systems, planetary governance, and unit group mechanics. Introduces governor profiles, fleet event lifecycles, end-of-turn population dynamics, beast hunt missions with trophy delivery, and unit selection infrastructure whilst refactoring PlanetData to centralise state mutations and delegating fragmented logic to cohesive handlers.

Changes

Cohort / File(s) Summary
Fleet Event Architecture
scripts/scr_fleet_events/*, objects/obj_en_fleet/Create_0.gml, objects/obj_en_fleet/Destroy_0.gml, objects/obj_en_fleet/Alarm_1.gml
Introduces FleetEvent constructor with timer-driven state machine (turn_sequence, destroy_sequence, fleet_event_functions map). Fleet instances now carry uid and events array. Serialization extended to rehydrate events from save data. obj_en_fleet draws now cache generated sprites in global.en_fleet_sprites.
PlanetData Refactor & End-of-Turn Systems
scripts/scr_PlanetData/scr_PlanetData.gml, scripts/scr_enemy_ai_b/scr_enemy_ai_b.gml, scripts/scr_enemy_ai_e/scr_enemy_ai_e.gml, scripts/scr_ork_fleet_functions/scr_ork_fleet_functions.gml
PlanetData now encapsulates end-of-turn population growth, influence/corruption dynamics, feature lifecycle, and garrison/saboteur management via static helpers (end_of_turn_population_influence_and_enemy_growth, end_turn_heretics_and_corruption_growth, check_old_battles_feature). Direct star/planet mutations replaced with PlanetData method calls.
Governor & Epithet System
scripts/scr_governors/*, scripts/scr_marine_struct/scr_marine_struct.gml, objects/obj_star/Create_0.gml
Introduces GovernorProfile constructor (uid, born, stats, gender, name via name_generator). Stars now hold p_governor as GovernorProfile array. Marines gain epithets array with add_epithet() and name_role() integration.
Unit Group & Role Selection
scripts/scr_UnitGroup_and_group_selection/*, scripts/is_specialist/is_specialist.gml (removed), objects/obj_controller/Alarm_5.gml, objects/obj_controller/Alarm_6.gml
New SearchConditions evaluator and UnitGroup class enable collect_role_group() and group_selection() flows. Removed legacy collect_role_group/stat_valuator/collect_by_religeon from is_specialist.gml and relocated to dedicated module. obj_controller recruitment logic refactored to use active_roles() cache.
Mission System: Beast Hunt & Trophy Delivery
scripts/scr_mission_functions/scr_mission_functions.gml, scripts/scr_cheatcode/scr_cheatcode.gml, scripts/scr_random_event/scr_random_event.gml
Adds init_beast_hunt_mission, complete_beast_hunt_mission, init_deliver_trophy_mission workflow with trophy epithet assignment. Trophy delivery now a timed fleet event with associated FleetEvent handlers (deliver_trophy_mission_timed_out, deliver_trophy_mission_fleet_destroyed). New planet_problem "deliver_trophy" added; add_new_problem() signature updated with defaults.
Fleet Functions & Strength Calculation
scripts/scr_fleet_functions/scr_fleet_functions.gml, scripts/scr_fleet_events/scr_fleet_events.gml, scripts/scr_mechanicus_fleet_functions/scr_mechanicus_fleet_functions.gml, scripts/scr_tau_fleet_functions/scr_tau_fleet_functions.gml, objects/obj_en_fleet/Step_0.gml
Centralised standard_fleet_strength_calc() replaces scattered capital/frigate/escort arithmetic. New get_fleet_uid() retrieves fleet by uid. Fleet arrival logic overhauled with merging/relocation for weakened Tau. Tau propaganda broadcast to planets via new tau_broadcast_propaganda_to_planet(). Mechanicus explore fleets spawn via spawn_mechanicus_explore_fleet().
UI & Drawing Overhaul
objects/obj_en_fleet/Draw_0.gml, objects/obj_star/Draw_0.gml, objects/obj_star_select/Draw_64.gml, scripts/scr_draw_planet_features/scr_draw_planet_features.gml, scripts/scr_buttons/scr_buttons.gml, scripts/scr_ui_manage/scr_ui_manage.gml
Sprite caching via global.en_fleet_sprites and global.star_sprites. add_draw_return_values() / pop_draw_return_values() wrapping for state stack management. obj_star_select refactored to use PlanetData and new draw_planet_population_controls() method. Forge assign/upgrade buttons introduced. Marine name rendered via ReactiveString with epithet.
Feature System: OldBattleGround
scripts/scr_planetary_feature/scr_planetary_feature.gml, scripts/scr_draw_planet_features/scr_draw_planet_features.gml, scripts/scr_mission_functions/scr_mission_functions.gml
New P_features.OldBattleGround enum member. Feature discovery and exploration scaffold. search_old_battle_grounds() integrates with Mechanicus fleet exploration. system_feature_bool now returns discovered system index rather than simple boolean.
Garrison & System Data Structures
objects/obj_star/Create_0.gml, scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml, scripts/scr_drop_select_function/scr_drop_select_function.gml, scripts/scr_garrison/scr_garrison.gml
Stars initialise system_datas, system_garrison, system_sabatours arrays. Garrison access pattern shifts from singular to plural (garrisons). PlanetData refresh_data() lifecycle replaces manual garrison creation. system_garrison now begins with [0] sentinel.
Helper Functions & Infrastructure
scripts/ds_map_helpers/ds_map_helpers.gml, scripts/scr_draw_text/scr_draw_text.gml, scripts/action_draw_ellipse/action_draw_ellipse.gml, scripts/instance_create/instance_create.gml, scripts/scr_hit/scr_hit.gml, scripts/scr_roman_numerals/scr_roman_numerals.gml, scripts/__init_global/__init_global.gml
New empty_ds_map() and ds_map_delete_sprite() helpers. draw_text_outline() now accepts scale parameter. draw_circle_with_outline_width() for circle stroke rendering. instance_at_location(), instance_distance(), nearest_instance() geometry helpers. scr_click_right() and unified click_controller(). irandom_numeral() for roman numeral rolls. global.en_fleet_sprites ds_map initialised.
Debug & Telemetry Removal
Multiple .gml files
Removed show_debug_message() calls throughout: obj_turn_end/Alarm_1, scr_recruit_data, scr_inquisition_mission, scr_mechanicus_missions, scr_trade, scr_shoot, scr_string_functions, scr_struct_functions, scr_ui_diplomacy, scr_cheatcode. Also removed quest save/load loops (50 Ongoing quest entries) from scr_save_controller and scr_load_controller.
Enemy AI Refactoring
scripts/scr_enemy_ai_c/scr_enemy_ai_c.gml, scripts/scr_enemy_ai_d/scr_enemy_ai_d.gml
Fleet strength calculations delegated to standard_fleet_strength_calc(). Local planet loop variable adjustments for garrison indexing consistency. Tau takeover messaging updated with planet_numeral_name() and disposition via eFACTION keys.
Removed Public APIs
scripts/is_specialist/is_specialist.gml
Removed collect_role_group, stat_valuator, collect_by_religeon, group_selection, and MissionSelectType enum. Functionality migrated to scr_UnitGroup_and_group_selection.
Manifest & Metadata
ChapterMaster.yyp, scripts/*/\*.yy, sprites/spr_fleet_*.yy
IDEVersion bumped to 2024.1400.0.904. Six new script resources registered (ds_map_helpers, scr_fleet_events, scr_governors, scr_mechanicus_fleet_functions, scr_tau_fleet_functions, scr_UnitGroup_and_group_selection). Sprite visibleRange fields set to null (formatting artifact).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested labels

Type: Feature, Area: Systems, Size: Epic

Suggested reviewers

  • EttyKitty
  • Blogaugis

Cogitatio Incognitus, Tech-Priest. The machine spirits have processed thy submission. This compendium of modifications runs deep through the architecture—fleet events now carry persistent memory-logs, governors birth from the void with whispered identities, and planetary systems pulse with orchestrated lifecycle rhythms. The refactoring of PlanetData into a centralised authority over all terrestrial state represents a significant crystallisation of scattered imperatives into unified dogma. Caution: the removal of logging telemetry hath obscured potential diagnostic channels. Proceed with reverent scrutiny, for the interconnections are manifold and inscrutable.

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description covers purpose, features added, and testing status, though formatting and clarity could be improved with better organisation and more structured bullet points.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed Title adheres to conventional commits format with type and concise summary; directly reflects PR objectives regarding multi-part missions and governor profiles.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 73

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (23)
scripts/scr_Table/scr_Table.gml (1)

96-99: CRITICAL MALFUNCTION DETECTED: Duplicate ritual invocation.

The hover() subroutine is executed twice when the cursor sanctifies a row, Tech-Priest. Lines 96-99 constitute redundant logic—this code fragment must be purged, as the restructured input handling at lines 100-115 already encompasses this functionality.

Impact: Performance degradation and potential state corruption if hover() possesses side effects.

⚙️ Requisite ablation sequence
 				}
-			}
-			if (_row_entered && struct_exists(_row,"hover")){
-				//show_debug_message($"click : {struct_exists(_row,"click_left")}");
-				_row.hover();
-			}
-			if (_row_entered){
+			}
+			if (_row_entered){
 				if (struct_exists(_row,"hover")){
objects/obj_controller/Draw_0.gml (1)

2-2: Ancient directive persists, Tech-Priest. Query: Shall I inscribe this task into the issue repository?

The TODO annotation indicates unresolved labour—the transference of draw operations to the GUI layer awaits completion.

Wouldst thou desire the creation of a tracking issue for this architectural migration?

scripts/scr_specialist_training/scr_specialist_training.gml (2)

265-265: The sacred refactor pattern has been violated here, Tech-Priest.

Whilst all other role invocations throughout this codex have been migrated to draw from the _roles array, this line still invokes the deprecated obj_ini.role[100,17] pattern. The _roles variable has been prepared at line 258, yet remains unutilised.

🔎 Rectification pattern for the inconsistency
-novice_type = string("{0} Aspirant",obj_ini.role[100,17]);
+novice_type = string("{0} Aspirant",_roles[17]);

3-431: The machine spirit observes repeated invocations of active_roles(), Tech-Priest.

This function is summoned six times across the specialist training rituals. Whilst each function's scope demands its own _roles binding, should active_roles() bear computational burden, consider passing _roles as a sacred parameter to the training functions rather than re-invoking the lookup ritual within each.

However, if active_roles() be but a simple array accessor, this pattern remains sound and maintainable.

scripts/scr_unit_quick_find_pane/scr_unit_quick_find_pane.gml (2)

448-448: Ambiguous equality operator, Tech-Priest. Verify the intent of this condition.

The Machine Spirit detects if (hide_sequence=30) — a single = within a conditional expression. In the arcane tongue of GML, this may evaluate as comparison, yet it invites confusion and potential error. If this is intended as equality check, the double sigil == is the sanctioned form for clarity.

🔎 Proposed clarification
-			if (hide_sequence=30) then hide_sequence=0;
+			if (hide_sequence==30) then hide_sequence=0;

128-231: The update_mission_log function grows in complexity, Tech-Priest.

The Machine Spirit notes that this function now handles multiple disparate data sources: planetary problems, controller quests, and fleet events. As new event types are added, consider whether extracting helper methods for each source type would preserve clarity and maintainability. The current implementation functions, but future expansion may warrant modularisation.

scripts/scr_struct_functions/scr_struct_functions.gml (1)

5-9: Ancient deprecated ritual awaits purging.

Tech-Priest, this deprecated function-relic bears the mark of deletion yet persists in the codex. The comment-scroll proclaims its obsolescence—it but wraps variable_clone() in vestigial ceremony.

Would you have this Machine Spirit open a sacred tracking-issue in your repository's archives to ensure this expungement is not forgotten? Or shall we proceed to excise it forthwith?

scripts/scr_system_search_helpers/scr_system_search_helpers.gml (1)

186-197: Critical logic corruption detected, Tech-Priest. The data-spirits cry out in anguish.

The conditional at lines 194-196 shall always evaluate true within this block, for _types_sort (which guards entry at line 186) equals array_length(types). Thus, any star marked _add = true by the loop shall be immediately overwritten to false. All stars with type filtering shall be rejected. This is a grievous malfunction.

🔧 Proposed litany of correction
 			if (_add && _types_sort){
 				_add = false;
 				for (var i=1;i<=planets;i++){
 					if (array_contains(types,p_type[i])){
 						_add = true;
 						break;
 					}
 				}
-				if (array_length(types)){
-					_add = false;
-				}				
 			}
objects/obj_controller/Alarm_6.gml (3)

52-59: CRITICAL HERESY DETECTED — Assignment operator corrupts conditional logic, Tech-Priest.

The Machine Spirit perceives a most grievous error. The single = operator performs assignment, not comparison. This heretical construct shall:

  1. Overwrite man[f] with "vehicle" for every iteration
  2. Overwrite ma_role[f] with each vehicle type string
  3. Corrupt the sacred data arrays and produce erroneous vehicle counts

In GML, equality comparison requires == or = only within if parentheses when intended as comparison — but the current syntax is ambiguous and dangerous.

🔧 Proposed sanctification of the code-runes
             // sets up count for the vehicles
             // TODO This needs to be extended to accomodate the selection text like the man ones
-            if (man[f]="vehicle"){
+            if (man[f]=="vehicle"){
                 vanz+=1;
-                if (ma_role[f]="Land Raider") then lrad+=1;
-                if (ma_role[f]="Rhino") then rhi+=1;
-                if (ma_role[f]="Predator") then pre+=1;
-                if (ma_role[f]="Land Speeder") then lspi+=1;
-                if (ma_role[f]="Whirlwind") then whi+=1;
+                if (ma_role[f]=="Land Raider") then lrad+=1;
+                if (ma_role[f]=="Rhino") then rhi+=1;
+                if (ma_role[f]=="Predator") then pre+=1;
+                if (ma_role[f]=="Land Speeder") then lspi+=1;
+                if (ma_role[f]=="Whirlwind") then whi+=1;
             }

85-89: Inconsistent data source for Librarian role designation, Tech-Priest.

The Machine Spirit observes that this block still invokes obj_ini.role[100,17] directly, whilst all other role references utilise the cached _roles array. This inconsistency violates the sanctified refactor pattern.

🔧 Proposed harmonisation
     if (lib>0){
-        selecting_dudes+=string(lib)+" "+string(obj_ini.role[100,17]);
+        selecting_dudes+=string(lib)+" "+string(_roles[17]);
         if (lib>1) then selecting_dudes+="s";
         selecting_dudes+=", ";
     }

214-214: CRITICAL HERESY — Assignment operator in conditional, Tech-Priest.

The Machine Spirit detects assignment (=) where comparison (==) is required. This construct shall:

  1. Assign -1 to sel_promoting
  2. Evaluate as truthy (non-zero)
  3. Then immediately overwrite with 0

The result: sel_promoting is always set to 0 at this juncture, regardless of its prior state.

🔧 Proposed sanctification
-    if (sel_promoting=-1) then sel_promoting=0;
+    if (sel_promoting==-1) then sel_promoting=0;
scripts/scr_event_code/scr_event_code.gml (1)

351-354: Inconsistent error pathway: exit versus return false.

Tech-Priest, the default case still uses exit whilst line 323 uses return false. This inconsistency violates the principle of uniform behaviour. The function should return false in all error paths.

🔎 Proposed harmonisation
 		default:
 			log_error("RE: Enemy, no faction could be chosen");
-			exit;
+			return false;
scripts/scr_buttons/scr_buttons.gml (1)

456-456: Unreachable code detected after return statement, Tech-Priest.

The pop_draw_return_values() invocation on line 456 exists beyond the conditional return statements (lines 451 and 454). This code shall never execute, leaving the draw state stack potentially corrupted.

🔎 Excision of dead code
         } else {
             pop_draw_return_values();
             return false;
         }
-        pop_draw_return_values();
     };
scripts/scr_marine_struct/scr_marine_struct.gml (1)

2013-2031: Critical logic corruption detected in name_role function, Tech-Priest.

The machine spirit perceives conflicting directives:

  1. Line 2024: The string "{temp_role} {name()}" lacks the sacred $ prefix for template interpolation. This shall produce literal text rather than variable substitution.

  2. Line 2030: The return statement invokes string("{0} {1}", temp_role, name()), discarding the _name variable constructed with epithet data (lines 2024-2029). The epithet logic is rendered vestigial.

🔎 Corrected logic pathway
     static name_role = function(include_epithet = true) {
         var temp_role = role();
         if (squad != "none") {
             if (struct_exists(obj_ini.squad_types[$ obj_ini.squads[squad].type], temp_role)) {
                 var role_info = obj_ini.squad_types[$ obj_ini.squads[squad].type][$ temp_role];
                 if (struct_exists(role_info, "role")) {
                     temp_role = role_info[$ "role"];
                 }
             }
         }

-        var _name = "{temp_role} {name()}";
+        var _name = $"{temp_role} {name()}";
         if (include_epithet){
             if (array_length(epithets)){
                 _name += $" {epithets[0].title}";
             }
         }
-        return string("{0} {1}", temp_role, name());
+        return _name;
     };
objects/obj_en_fleet/Alarm_1.gml (1)

10-10: Observation: TODO marker detected, Tech-Priest.

This cogitator observes a TODO directive regarding the centralisation of orbiting logic. Dost thou wish this unit to generate an issue within the sacred archives of GitHub to track this pending rite of code refinement?

scripts/scr_enemy_ai_d/scr_enemy_ai_d.gml (1)

449-458: CRITICAL MALFUNCTION DETECTED, TECH-PRIEST!

The machine spirit perceives a grievous error in the loop construct. The variable planet is declared with value 1, yet the loop condition i<=planets and increment i++ operate upon i - a variable from a prior loop scope. Furthermore, planet never receives increment, causing system_garrison[planet] to eternally reference index 1.

This shall cause incorrect garrison processing and potentially undefined behaviour when i exceeds planets.

🔎 Proposed corrective rite
 	// Local problems will go here
 	var planet;
-	for (var planet=1;i<=planets;i++){
+	for (var planet=1;planet<=planets;planet++){
 		if (i < array_length(system_garrison)){
-			var garrison = system_garrison[planet];
+			var garrison = system_garrison[planet];
 			if (garrison.garrison_force){
 				if (garrison.garrison_disposition_change(self,planet)!="none"){
 					dispo[planet]+=garrison.dispo_change;
 				}
 			}
 		}
 	}

Additionally, line 450 should use planet instead of i for the bounds check:

-		if (i < array_length(system_garrison)){
+		if (planet < array_length(system_garrison)){
scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml (1)

248-263: default_imperium_attack ternary is dense; consider making the intent more explicit

Tech-Priest, this line encodes a non‑trivial doctrinal rule in a compact ternary:

default_imperium_attack = guard_score>0 && !((guard_score<=0.5) && (pdf_score>0)) ?"guard":"pdf";

While correct, the nested condition and inline ternary are not immediately self‑evident to lesser adepts.

Would it aid future maintenance to extract the predicate into a named boolean, e.g. var guard_preferred = ...; followed by a simpler if/else, so the choice between Guard and PDF becomes narratively clear in the code rather than encoded as a riddle?

scripts/scr_enemy_ai_b/scr_enemy_ai_b.gml (1)

95-107: String interpolation and Low Gothic corruption detected

Tech-Priest, the alert incantation at line 96 manifests two grievances:

  • The string "Planet {planet_numeral_name(i)} ..." lacketh the $ prefix, rendering {planet_numeral_name(i)} as inert runes rather than executable function call.
  • The phrase "has succeed ed" deviates from proper Gothic syntax; the correct declension is "seceded".

Refactor to:

scr_alert("red", "owner", $"Planet {planet_numeral_name(i)} has seceded to the Tau Empire!", x, y);
objects/obj_star/Create_0.gml (1)

64-76: Rectify the GovernorProfile array indexing to align with the 1-based planetary schema

Tech-Priest, the initialisation of p_governor deviates catastrophically from the established pattern. The array is first created with _planet_array_size entries, then obliterated and rebuilt with array_push, yielding indices 0..6 (seven entries). Yet the rest of thy codebase accesses planets via 1-based indexing—when code invokes p_governor[planet] with planet ∈ [1..8], it encounters a void at index 8, and the logic collapses into undefined darkness.

All sibling arrays (p_operatives, p_features, etc.) maintain the proper shape: nine slots indexed 0..8, with indices 1..8 bearing data. Restore p_governor to this sanctified form:

- p_governor = array_create(_planet_array_size, "");
+ p_governor = array_create(_planet_array_size);

- p_governor = [];
-
-for (var i=1;i<8;i++){
-    array_push(p_governor, new GovernorProfile());
-}
+for (var i = 1; i < _planet_array_size; i++){
+    p_governor[i] = new GovernorProfile();
+}

This ensures every planetary slot 1..8 receives its GovernorProfile and prevents undefined memory access.

scripts/scr_random_event/scr_random_event.gml (1)

644-679: Unreachable code detected, Tech-Priest.

The cogitator's logic-pathways reveal a discrepancy most grave. Cases 10 (Heretics) and 13 (Necron) at lines 666-675 shall never execute, for the enemy selection at line 646 invokes only choose(7,8,9). These xenos and heretical spawn remain forever dormant in the code-scriptures.

Was this deliberate pruning of the enemy roster, or does the Machine Spirit sense an incomplete implementation?

scripts/scr_mission_functions/scr_mission_functions.gml (1)

990-1008: Critical logic error in add_new_problem function.

Tech-Priest, a most grievous corruption exists at line 994. The condition p_problem[planet][i] == timer should be p_problem[planet][i] == "" to find an empty slot. Currently, this seeks a slot containing the timer value, which will virtually never match, causing problems to never be added.

🔎 Urgent correction required
 	if (star=="none"){
 		for (var i=0;i<array_length(p_problem[planet]);i++){
-			if (p_problem[planet][i] == timer){
+			if (p_problem[planet][i] == ""){
 				p_problem[planet][i]= problem;
 				p_problem_other_data[planet][i]=other_data;
 				p_timer[planet][i] = timer;
scripts/scr_PlanetData/scr_PlanetData.gml (2)

557-563: Refactor: Sanctify this logic within a proper ritual, Tech-Priest.

The machine spirit detects orphaned code-canticles within the constructor corpus. This population-zero reset logic dwells outside method boundaries, executing with each instantiation. Consider relocating this doctrine into refresh_data or a dedicated static purification method.

⚙️ Proposed restructuring

Move this logic into a static method:

+    static purge_empty_planet_corruption = function(){
+        if (population == 0) {
+            system.p_heresy[planet] = 0;
+            system.p_heresy_secret[planet] = 0;
+            for (var i = 0; i < array_length(system.p_influence[planet]); ++i) {
+                system.p_influence[planet][i] = 0;
+            }
+        }
+    }

Then invoke within refresh_data or at the conclusion of population mutations.


324-554: Consider decomposition of complex ork growth ritual, Tech-Priest.

The grow_ork_forces incantation spans 230 lines with multiple nested conditionals and repeated reassignment of the _rando designation. The machine spirit suggests partitioning this ceremony into smaller sub-rituals:

  • Ork population growth calculation
  • Ork spreading mechanics
  • Stronghold and Warboss evolution
  • Fleet construction logic
  • Waaagh departure sequence

This shall enhance clarity and ease future maintenance of the greenskin propagation algorithms.

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcedde6 and 3038c4a.

📒 Files selected for processing (79)
  • ChapterMaster.yyp
  • objects/obj_controller/Alarm_5.gml
  • objects/obj_controller/Alarm_6.gml
  • objects/obj_controller/CleanUp_0.gml
  • objects/obj_controller/Draw_0.gml
  • objects/obj_en_fleet/Alarm_1.gml
  • objects/obj_en_fleet/Create_0.gml
  • objects/obj_en_fleet/Destroy_0.gml
  • objects/obj_en_fleet/Draw_0.gml
  • objects/obj_en_fleet/Step_0.gml
  • objects/obj_ncombat/Alarm_1.gml
  • objects/obj_star/Create_0.gml
  • objects/obj_star/Draw_0.gml
  • objects/obj_star_select/Draw_64.gml
  • objects/obj_timer/Create_0.gml
  • objects/obj_turn_end/Alarm_1.gml
  • scripts/__init_global/__init_global.gml
  • scripts/action_draw_ellipse/action_draw_ellipse.gml
  • scripts/ds_map_helpers/ds_map_helpers.gml
  • scripts/ds_map_helpers/ds_map_helpers.yy
  • scripts/instance_create/instance_create.gml
  • scripts/is_specialist/is_specialist.gml
  • scripts/scr_ChapterTraits/scr_ChapterTraits.gml
  • scripts/scr_PlanetData/scr_PlanetData.gml
  • scripts/scr_Table/scr_Table.gml
  • scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.gml
  • scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.yy
  • scripts/scr_apothecary_ground/scr_apothecary_ground.gml
  • scripts/scr_buttons/scr_buttons.gml
  • scripts/scr_chapter_managent_events/scr_chapter_managent_events.gml
  • scripts/scr_cheatcode/scr_cheatcode.gml
  • scripts/scr_draw_planet_features/scr_draw_planet_features.gml
  • scripts/scr_draw_text/scr_draw_text.gml
  • scripts/scr_drop_select_function/scr_drop_select_function.gml
  • scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml
  • scripts/scr_enemy_ai_b/scr_enemy_ai_b.gml
  • scripts/scr_enemy_ai_c/scr_enemy_ai_c.gml
  • scripts/scr_enemy_ai_d/scr_enemy_ai_d.gml
  • scripts/scr_enemy_ai_e/scr_enemy_ai_e.gml
  • scripts/scr_event_code/scr_event_code.gml
  • scripts/scr_fleet_events/scr_fleet_events.gml
  • scripts/scr_fleet_events/scr_fleet_events.yy
  • scripts/scr_fleet_functions/scr_fleet_functions.gml
  • scripts/scr_forge_world_functions/scr_forge_world_functions.gml
  • scripts/scr_garrison/scr_garrison.gml
  • scripts/scr_governors/scr_governors.gml
  • scripts/scr_governors/scr_governors.yy
  • scripts/scr_hit/scr_hit.gml
  • scripts/scr_imperial_navy_functions/scr_imperial_navy_functions.gml
  • scripts/scr_inquisition_mission/scr_inquisition_mission.gml
  • scripts/scr_khornate_fleet_functions/scr_khornate_fleet_functions.gml
  • scripts/scr_load_controller/scr_load_controller.gml
  • scripts/scr_marine_struct/scr_marine_struct.gml
  • scripts/scr_mechanicus_fleet_functions/scr_mechanicus_fleet_functions.gml
  • scripts/scr_mechanicus_fleet_functions/scr_mechanicus_fleet_functions.yy
  • scripts/scr_mechanicus_missions/scr_mechanicus_missions.gml
  • scripts/scr_mission_functions/scr_mission_functions.gml
  • scripts/scr_ork_fleet_functions/scr_ork_fleet_functions.gml
  • scripts/scr_planetary_feature/scr_planetary_feature.gml
  • scripts/scr_player_fleet_functions/scr_player_fleet_functions.gml
  • scripts/scr_purge_world/scr_purge_world.gml
  • scripts/scr_random_event/scr_random_event.gml
  • scripts/scr_recruit_data/scr_recruit_data.gml
  • scripts/scr_roman_numerals/scr_roman_numerals.gml
  • scripts/scr_save_controller/scr_save_controller.gml
  • scripts/scr_shoot/scr_shoot.gml
  • scripts/scr_specialist_training/scr_specialist_training.gml
  • scripts/scr_string_functions/scr_string_functions.gml
  • scripts/scr_struct_functions/scr_struct_functions.gml
  • scripts/scr_system_search_helpers/scr_system_search_helpers.gml
  • scripts/scr_tau_fleet_functions/scr_tau_fleet_functions.gml
  • scripts/scr_tau_fleet_functions/scr_tau_fleet_functions.yy
  • scripts/scr_trade/scr_trade.gml
  • scripts/scr_trade_dep/scr_trade_dep.gml
  • scripts/scr_ui_diplomacy/scr_ui_diplomacy.gml
  • scripts/scr_ui_manage/scr_ui_manage.gml
  • scripts/scr_unit_quick_find_pane/scr_unit_quick_find_pane.gml
  • sprites/spr_fleet_imperial/spr_fleet_imperial.yy
  • sprites/spr_fleet_tau/spr_fleet_tau.yy
💤 Files with no reviewable changes (12)
  • scripts/scr_shoot/scr_shoot.gml
  • scripts/scr_recruit_data/scr_recruit_data.gml
  • scripts/scr_load_controller/scr_load_controller.gml
  • scripts/scr_inquisition_mission/scr_inquisition_mission.gml
  • scripts/scr_ui_diplomacy/scr_ui_diplomacy.gml
  • scripts/scr_string_functions/scr_string_functions.gml
  • scripts/is_specialist/is_specialist.gml
  • scripts/scr_trade_dep/scr_trade_dep.gml
  • objects/obj_turn_end/Alarm_1.gml
  • objects/obj_timer/Create_0.gml
  • scripts/scr_ChapterTraits/scr_ChapterTraits.gml
  • scripts/scr_save_controller/scr_save_controller.gml
🧰 Additional context used
📓 Path-based instructions (3)
**/*.gml

⚙️ CodeRabbit configuration file

**/*.gml: - Constants of macro type MUST have a space between the constant name and its value. Without it, the compiler will throw an error.

  • WRONG: #macro COLOR_RED11119
  • RIGHT: #macro COLOR_RED 11119
  • Color codes in the code SHOULDN'T have any spaces in their ID.
    • WRONG: # 80bf40
    • RIGHT: #80bf40
  • All code should comply with the up-to-date GML documentation.

Files:

  • scripts/__init_global/__init_global.gml
  • scripts/scr_mechanicus_missions/scr_mechanicus_missions.gml
  • scripts/scr_struct_functions/scr_struct_functions.gml
  • scripts/action_draw_ellipse/action_draw_ellipse.gml
  • objects/obj_en_fleet/Destroy_0.gml
  • objects/obj_en_fleet/Alarm_1.gml
  • scripts/ds_map_helpers/ds_map_helpers.gml
  • scripts/scr_mechanicus_fleet_functions/scr_mechanicus_fleet_functions.gml
  • scripts/scr_drop_select_function/scr_drop_select_function.gml
  • scripts/scr_specialist_training/scr_specialist_training.gml
  • objects/obj_controller/CleanUp_0.gml
  • scripts/scr_trade/scr_trade.gml
  • scripts/scr_draw_text/scr_draw_text.gml
  • scripts/scr_fleet_functions/scr_fleet_functions.gml
  • scripts/scr_tau_fleet_functions/scr_tau_fleet_functions.gml
  • scripts/scr_enemy_ai_c/scr_enemy_ai_c.gml
  • scripts/scr_roman_numerals/scr_roman_numerals.gml
  • scripts/instance_create/instance_create.gml
  • scripts/scr_fleet_events/scr_fleet_events.gml
  • scripts/scr_buttons/scr_buttons.gml
  • scripts/scr_purge_world/scr_purge_world.gml
  • scripts/scr_hit/scr_hit.gml
  • scripts/scr_apothecary_ground/scr_apothecary_ground.gml
  • objects/obj_star/Draw_0.gml
  • scripts/scr_planetary_feature/scr_planetary_feature.gml
  • scripts/scr_random_event/scr_random_event.gml
  • scripts/scr_player_fleet_functions/scr_player_fleet_functions.gml
  • scripts/scr_imperial_navy_functions/scr_imperial_navy_functions.gml
  • scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.gml
  • scripts/scr_ork_fleet_functions/scr_ork_fleet_functions.gml
  • scripts/scr_enemy_ai_e/scr_enemy_ai_e.gml
  • objects/obj_ncombat/Alarm_1.gml
  • objects/obj_controller/Alarm_6.gml
  • objects/obj_star/Create_0.gml
  • scripts/scr_ui_manage/scr_ui_manage.gml
  • objects/obj_star_select/Draw_64.gml
  • scripts/scr_draw_planet_features/scr_draw_planet_features.gml
  • objects/obj_en_fleet/Step_0.gml
  • scripts/scr_Table/scr_Table.gml
  • scripts/scr_governors/scr_governors.gml
  • scripts/scr_chapter_managent_events/scr_chapter_managent_events.gml
  • scripts/scr_unit_quick_find_pane/scr_unit_quick_find_pane.gml
  • objects/obj_en_fleet/Create_0.gml
  • scripts/scr_system_search_helpers/scr_system_search_helpers.gml
  • scripts/scr_marine_struct/scr_marine_struct.gml
  • objects/obj_en_fleet/Draw_0.gml
  • scripts/scr_garrison/scr_garrison.gml
  • scripts/scr_enemy_ai_d/scr_enemy_ai_d.gml
  • objects/obj_controller/Alarm_5.gml
  • scripts/scr_PlanetData/scr_PlanetData.gml
  • scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml
  • scripts/scr_event_code/scr_event_code.gml
  • scripts/scr_forge_world_functions/scr_forge_world_functions.gml
  • scripts/scr_khornate_fleet_functions/scr_khornate_fleet_functions.gml
  • scripts/scr_enemy_ai_b/scr_enemy_ai_b.gml
  • scripts/scr_mission_functions/scr_mission_functions.gml
  • scripts/scr_cheatcode/scr_cheatcode.gml
  • objects/obj_controller/Draw_0.gml
**/*.*

⚙️ CodeRabbit configuration file

**/*.*: - Do not prioritize the shortest code. Prioritize code that explicitly reveals its intent.

  • Understandable variable naming is extremely important.
  • If a solution is "clever" but hard to parse mentally, request a refactor to a more verbose but clearer approach.
  • Apply the "Rule of Three": suggest abstraction when logic is repeated three times or more times.
  • For subjective improvements (naming, architectural choice), do not give a concrete suggestion immediately. Instead, ask a guiding question to prompt the user's reflection.
  • Every suggestion for a code change must include a brief justification.
  • If a TODO comment is added, ask the user if you should create a GitHub issue for this TODO.
  • If a TODO comment is deleted, remind the user if there is an active GitHub issue related to that comment.

Files:

  • scripts/__init_global/__init_global.gml
  • scripts/scr_mechanicus_missions/scr_mechanicus_missions.gml
  • scripts/scr_struct_functions/scr_struct_functions.gml
  • scripts/scr_fleet_events/scr_fleet_events.yy
  • scripts/action_draw_ellipse/action_draw_ellipse.gml
  • objects/obj_en_fleet/Destroy_0.gml
  • objects/obj_en_fleet/Alarm_1.gml
  • scripts/ds_map_helpers/ds_map_helpers.yy
  • scripts/ds_map_helpers/ds_map_helpers.gml
  • scripts/scr_mechanicus_fleet_functions/scr_mechanicus_fleet_functions.gml
  • scripts/scr_drop_select_function/scr_drop_select_function.gml
  • sprites/spr_fleet_tau/spr_fleet_tau.yy
  • scripts/scr_specialist_training/scr_specialist_training.gml
  • objects/obj_controller/CleanUp_0.gml
  • scripts/scr_trade/scr_trade.gml
  • scripts/scr_draw_text/scr_draw_text.gml
  • scripts/scr_fleet_functions/scr_fleet_functions.gml
  • scripts/scr_tau_fleet_functions/scr_tau_fleet_functions.gml
  • scripts/scr_enemy_ai_c/scr_enemy_ai_c.gml
  • scripts/scr_roman_numerals/scr_roman_numerals.gml
  • scripts/instance_create/instance_create.gml
  • scripts/scr_fleet_events/scr_fleet_events.gml
  • scripts/scr_buttons/scr_buttons.gml
  • scripts/scr_purge_world/scr_purge_world.gml
  • scripts/scr_hit/scr_hit.gml
  • scripts/scr_apothecary_ground/scr_apothecary_ground.gml
  • objects/obj_star/Draw_0.gml
  • scripts/scr_mechanicus_fleet_functions/scr_mechanicus_fleet_functions.yy
  • scripts/scr_planetary_feature/scr_planetary_feature.gml
  • scripts/scr_random_event/scr_random_event.gml
  • scripts/scr_player_fleet_functions/scr_player_fleet_functions.gml
  • scripts/scr_imperial_navy_functions/scr_imperial_navy_functions.gml
  • scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.gml
  • scripts/scr_ork_fleet_functions/scr_ork_fleet_functions.gml
  • scripts/scr_enemy_ai_e/scr_enemy_ai_e.gml
  • objects/obj_ncombat/Alarm_1.gml
  • objects/obj_controller/Alarm_6.gml
  • objects/obj_star/Create_0.gml
  • scripts/scr_ui_manage/scr_ui_manage.gml
  • objects/obj_star_select/Draw_64.gml
  • scripts/scr_draw_planet_features/scr_draw_planet_features.gml
  • objects/obj_en_fleet/Step_0.gml
  • scripts/scr_Table/scr_Table.gml
  • scripts/scr_governors/scr_governors.gml
  • scripts/scr_chapter_managent_events/scr_chapter_managent_events.gml
  • scripts/scr_unit_quick_find_pane/scr_unit_quick_find_pane.gml
  • objects/obj_en_fleet/Create_0.gml
  • scripts/scr_system_search_helpers/scr_system_search_helpers.gml
  • scripts/scr_marine_struct/scr_marine_struct.gml
  • ChapterMaster.yyp
  • objects/obj_en_fleet/Draw_0.gml
  • scripts/scr_garrison/scr_garrison.gml
  • sprites/spr_fleet_imperial/spr_fleet_imperial.yy
  • scripts/scr_enemy_ai_d/scr_enemy_ai_d.gml
  • objects/obj_controller/Alarm_5.gml
  • scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.yy
  • scripts/scr_PlanetData/scr_PlanetData.gml
  • scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml
  • scripts/scr_event_code/scr_event_code.gml
  • scripts/scr_forge_world_functions/scr_forge_world_functions.gml
  • scripts/scr_khornate_fleet_functions/scr_khornate_fleet_functions.gml
  • scripts/scr_enemy_ai_b/scr_enemy_ai_b.gml
  • scripts/scr_governors/scr_governors.yy
  • scripts/scr_mission_functions/scr_mission_functions.gml
  • scripts/scr_cheatcode/scr_cheatcode.gml
  • scripts/scr_tau_fleet_functions/scr_tau_fleet_functions.yy
  • objects/obj_controller/Draw_0.gml
**/*.yy

⚙️ CodeRabbit configuration file

**/*.yy: 1. When any script or sprite .yy files are deleted, their paths should also be deleted from the project .yyp file, otherwise the game will crash.
2. When any script or sprite .yy files are created, their paths should be added to the project .yyp file, otherwise they'll fail.

Files:

  • scripts/scr_fleet_events/scr_fleet_events.yy
  • scripts/ds_map_helpers/ds_map_helpers.yy
  • sprites/spr_fleet_tau/spr_fleet_tau.yy
  • scripts/scr_mechanicus_fleet_functions/scr_mechanicus_fleet_functions.yy
  • sprites/spr_fleet_imperial/spr_fleet_imperial.yy
  • scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.yy
  • scripts/scr_governors/scr_governors.yy
  • scripts/scr_tau_fleet_functions/scr_tau_fleet_functions.yy
🧠 Learnings (19)
📚 Learning: 2025-09-04T14:37:58.773Z
Learnt from: CR
Repo: Adeptus-Dominus/ChapterMaster PR: 0
File: docs/CODE_STYLE.md:0-0
Timestamp: 2025-09-04T14:37:58.773Z
Learning: Applies to docs/**/*.gml : File names should follow GameMaker type-prefix conventions

Applied to files:

  • scripts/scr_fleet_events/scr_fleet_events.yy
  • scripts/scr_tau_fleet_functions/scr_tau_fleet_functions.yy
📚 Learning: 2025-09-04T14:37:58.773Z
Learnt from: CR
Repo: Adeptus-Dominus/ChapterMaster PR: 0
File: docs/CODE_STYLE.md:0-0
Timestamp: 2025-09-04T14:37:58.773Z
Learning: Applies to docs/**/scr_*_functions.gml : Prefer storing scripts in library-like files named scr_*_functions.gml

Applied to files:

  • scripts/scr_fleet_events/scr_fleet_events.yy
  • scripts/scr_drop_select_function/scr_drop_select_function.gml
  • scripts/scr_fleet_events/scr_fleet_events.gml
  • scripts/scr_buttons/scr_buttons.gml
  • scripts/scr_mechanicus_fleet_functions/scr_mechanicus_fleet_functions.yy
  • scripts/scr_chapter_managent_events/scr_chapter_managent_events.gml
  • ChapterMaster.yyp
  • scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.yy
  • scripts/scr_governors/scr_governors.yy
  • scripts/scr_tau_fleet_functions/scr_tau_fleet_functions.yy
📚 Learning: 2025-03-31T23:32:30.003Z
Learnt from: OH296
Repo: Adeptus-Dominus/ChapterMaster PR: 646
File: objects/obj_pnunit/Alarm_5.gml:84-91
Timestamp: 2025-03-31T23:32:30.003Z
Learning: In obj_pnunit/Alarm_5.gml, the function get_armour_data("maintenance") will always return a numeric value (at minimum 0), making null/undefined checks unnecessary.

Applied to files:

  • objects/obj_en_fleet/Alarm_1.gml
  • objects/obj_ncombat/Alarm_1.gml
  • objects/obj_controller/Alarm_6.gml
  • objects/obj_controller/Alarm_5.gml
📚 Learning: 2025-03-31T15:41:45.611Z
Learnt from: EttyKitty
Repo: Adeptus-Dominus/ChapterMaster PR: 649
File: objects/obj_enunit/Alarm_0.gml:289-291
Timestamp: 2025-03-31T15:41:45.611Z
Learning: GameMaker Studio's function `action_if_variable(image_index, -500, 0)` is auto-generated code from GameMaker's visual Drag and Drop system. It checks if image_index equals -500. In ChapterMaster, this was being used as a special flag for enemy unit movement, but wasn't triggering consistently, causing enemies to move only every other turn. The refactored code replaced this with direct function calls at specific combat stages.

Applied to files:

  • objects/obj_en_fleet/Alarm_1.gml
  • scripts/scr_enemy_ai_c/scr_enemy_ai_c.gml
  • scripts/scr_player_fleet_functions/scr_player_fleet_functions.gml
  • scripts/scr_imperial_navy_functions/scr_imperial_navy_functions.gml
  • objects/obj_en_fleet/Step_0.gml
  • objects/obj_en_fleet/Draw_0.gml
  • scripts/scr_enemy_ai_d/scr_enemy_ai_d.gml
📚 Learning: 2025-03-31T15:41:45.611Z
Learnt from: EttyKitty
Repo: Adeptus-Dominus/ChapterMaster PR: 649
File: objects/obj_enunit/Alarm_0.gml:289-291
Timestamp: 2025-03-31T15:41:45.611Z
Learning: GameMaker Studio's function `action_if_variable(image_index, -500, 0)` was part of an old enemy movement system in ChapterMaster. This syntax is auto-generated from GameMaker's Drag-and-Drop interface and checks if image_index is greater than or equal to -500. In the refactored code, enemy movement is triggered directly through function calls rather than relying on this conditional check.

Applied to files:

  • objects/obj_en_fleet/Alarm_1.gml
  • objects/obj_en_fleet/Step_0.gml
  • scripts/scr_enemy_ai_d/scr_enemy_ai_d.gml
📚 Learning: 2025-03-07T01:56:40.971Z
Learnt from: MCPO-Spartan-117
Repo: Adeptus-Dominus/ChapterMaster PR: 562
File: scripts/scr_marine_struct/scr_marine_struct.gml:0-0
Timestamp: 2025-03-07T01:56:40.971Z
Learning: Marines' ages should be incremented at the year transition in obj_turn_end/Alarm_1.gml rather than calculated dynamically based on the current year and recruitment date. This ensures proper aging without retroactive application.

Applied to files:

  • objects/obj_en_fleet/Alarm_1.gml
  • scripts/scr_specialist_training/scr_specialist_training.gml
  • objects/obj_ncombat/Alarm_1.gml
  • objects/obj_controller/Alarm_6.gml
  • objects/obj_controller/Alarm_5.gml
📚 Learning: 2025-04-15T10:54:19.720Z
Learnt from: VanWeapon
Repo: Adeptus-Dominus/ChapterMaster PR: 725
File: scripts/scr_special_view/scr_special_view.gml:49-49
Timestamp: 2025-04-15T10:54:19.720Z
Learning: In the ChapterMaster codebase, obj_ini.role[100][2] and obj_ini.role[100][eROLE.ChapterMaster] reference different roles, and both are needed in conditions checking for specific types of units. Numeric indices should not be assumed to match their corresponding enum values without verification.

Applied to files:

  • scripts/scr_specialist_training/scr_specialist_training.gml
  • objects/obj_ncombat/Alarm_1.gml
  • objects/obj_controller/Alarm_6.gml
  • objects/obj_controller/Alarm_5.gml
📚 Learning: 2025-02-24T07:38:42.267Z
Learnt from: MCPO-Spartan-117
Repo: Adeptus-Dominus/ChapterMaster PR: 508
File: scripts/scr_specialist_training/scr_specialist_training.gml:371-371
Timestamp: 2025-02-24T07:38:42.267Z
Learning: The spec_train_data array index for Techmarine training data is 0, as confirmed by the maintainer.

Applied to files:

  • scripts/scr_specialist_training/scr_specialist_training.gml
📚 Learning: 2025-09-04T14:37:58.773Z
Learnt from: CR
Repo: Adeptus-Dominus/ChapterMaster PR: 0
File: docs/CODE_STYLE.md:0-0
Timestamp: 2025-09-04T14:37:58.773Z
Learning: Applies to docs/**/*.gml : Prefer a group prefix at the start of function/script names (e.g., string_convert, fleet_explode)

Applied to files:

  • scripts/scr_fleet_events/scr_fleet_events.gml
  • scripts/scr_mechanicus_fleet_functions/scr_mechanicus_fleet_functions.yy
  • scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.gml
  • scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.yy
📚 Learning: 2025-09-04T14:52:45.005Z
Learnt from: OH296
Repo: Adeptus-Dominus/ChapterMaster PR: 0
File: :0-0
Timestamp: 2025-09-04T14:52:45.005Z
Learning: Project coding style summary:
- Constructors PascalCase; functions/variables snake_case with group prefixes (scr_*).
- Enums: enum name eNAME in SNAKE_CASE; entries PascalCase.
- Macros: ALL_CAPS SNAKE_CASE.
- Indentation 4 spaces; semicolons; use &&/||; parentheses for mixed ops; prefer ++/--.
- Prefer template strings $"..."; use “///” doc comments.
- Locals recommended with leading underscore.
- Organize scripts into library-like files; use early returns and init vars at declaration.

Applied to files:

  • scripts/scr_buttons/scr_buttons.gml
  • scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.yy
📚 Learning: 2025-06-16T17:12:13.045Z
Learnt from: EttyKitty
Repo: Adeptus-Dominus/ChapterMaster PR: 878
File: scripts/scr_culture_visuals/scr_culture_visuals.gml:1256-1352
Timestamp: 2025-06-16T17:12:13.045Z
Learning: In scripts/scr_culture_visuals/scr_culture_visuals.gml, the weapon visual data declarations contain known DRY violations that are acknowledged by the development team but deferred to future refactoring efforts rather than addressed in individual feature PRs.

Applied to files:

  • scripts/scr_buttons/scr_buttons.gml
📚 Learning: 2025-04-18T13:33:54.167Z
Learnt from: EttyKitty
Repo: Adeptus-Dominus/ChapterMaster PR: 0
File: :0-0
Timestamp: 2025-04-18T13:33:54.167Z
Learning: In obj_new_button/Step_0.gml, when using scr_click_left() for detecting clicks on menu buttons, it should be called with parameter 0 (scr_click_left(0)) to disable the default cooldown of 60 steps. Using the default cooldown can cause menu buttons to appear unresponsive since it prevents subsequent clicks from being detected.

Applied to files:

  • scripts/scr_hit/scr_hit.gml
  • objects/obj_controller/Draw_0.gml
📚 Learning: 2025-04-18T19:18:34.387Z
Learnt from: EttyKitty
Repo: Adeptus-Dominus/ChapterMaster PR: 734
File: objects/obj_creation/Draw_0.gml:765-771
Timestamp: 2025-04-18T19:18:34.387Z
Learning: When refactoring mouse input in ChapterMaster, prefer using the `point_and_click([x1, y1, x2, y2])` function rather than `scr_click_left(0)` for UI elements. Setting a cooldown of 0 is problematic as it removes click protection, whereas `point_and_click()` uses a default cooldown of 60 and combines rectangle bounds checking with click detection.

Applied to files:

  • scripts/scr_hit/scr_hit.gml
📚 Learning: 2025-03-20T22:22:57.319Z
Learnt from: EttyKitty
Repo: Adeptus-Dominus/ChapterMaster PR: 0
File: :0-0
Timestamp: 2025-03-20T22:22:57.319Z
Learning: In the ChapterMaster game PR #424, the psychic power system was changed to be data-driven, with perils now able to occur on both successful and failed casts but with reduced frequency overall.

Applied to files:

  • scripts/scr_random_event/scr_random_event.gml
  • ChapterMaster.yyp
📚 Learning: 2025-03-11T01:34:29.268Z
Learnt from: EttyKitty
Repo: Adeptus-Dominus/ChapterMaster PR: 579
File: objects/obj_enunit/Alarm_0.gml:186-187
Timestamp: 2025-03-11T01:34:29.268Z
Learning: In the ChapterMaster game, the variable `_column_size_value` represents the physical size/mass of a column of units, calculated as (vehicles * 2.5) + (dreadnoughts * 2) + (men * 0.5), and is used for determining back row protection rules.

Applied to files:

  • objects/obj_controller/Alarm_6.gml
📚 Learning: 2025-04-16T09:51:55.065Z
Learnt from: EttyKitty
Repo: Adeptus-Dominus/ChapterMaster PR: 0
File: :0-0
Timestamp: 2025-04-16T09:51:55.065Z
Learning: In obj_ingame_menu/Step_0.gml, the line "if (effect=14){instance_create(0,0,obj_fade);fading=0.1;}" must not be commented out, as it's critical for menu button transitions. When clicking the Exit button, it sets effect=14, but without this handler creating the fade effect object, no transition occurs.

Applied to files:

  • scripts/scr_draw_planet_features/scr_draw_planet_features.gml
  • objects/obj_en_fleet/Draw_0.gml
  • objects/obj_controller/Draw_0.gml
📚 Learning: 2025-03-01T11:06:25.427Z
Learnt from: MCPO-Spartan-117
Repo: Adeptus-Dominus/ChapterMaster PR: 526
File: objects/obj_popup/Draw_0.gml:234-239
Timestamp: 2025-03-01T11:06:25.427Z
Learning: The comment "Need to modify ^^^^ based on if it is chaos or daemonic" in the artifact gifting code is intentionally kept as a reminder that this implementation is not yet finished, despite the significant refactoring already done.

Applied to files:

  • scripts/scr_event_code/scr_event_code.gml
📚 Learning: 2025-09-04T14:37:58.773Z
Learnt from: CR
Repo: Adeptus-Dominus/ChapterMaster PR: 0
File: docs/CODE_STYLE.md:0-0
Timestamp: 2025-09-04T14:37:58.773Z
Learning: Applies to docs/**/*.gml : Avoid creating a separate file for every small script

Applied to files:

  • scripts/scr_governors/scr_governors.yy
📚 Learning: 2025-04-15T10:51:31.955Z
Learnt from: VanWeapon
Repo: Adeptus-Dominus/ChapterMaster PR: 725
File: datafiles/main/chapters/10.JSON:281-346
Timestamp: 2025-04-15T10:51:31.955Z
Learning: GameMaker Language (GML) JSON parser accepts trailing commas in JSON files, unlike standard JSON parsers which consider them syntax errors. When reviewing JSON files in this codebase, trailing commas should not be flagged as issues.

Applied to files:

  • scripts/scr_tau_fleet_functions/scr_tau_fleet_functions.yy

Comment on lines 75 to 79
if (champ>0){
selecting_dudes+=$"{champ} {obj_ini.role[100][eROLE.Ancient]}";
selecting_dudes+=$"{champ} {_roles[eROLE.Ancient]}";
if (chap>1) then selecting_dudes+="s";
selecting_dudes+=", ";
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Logic corruption in Ancient pluralisation, Tech-Priest.

The Machine Spirit detects a transcription error. The block assembles text for champ (Ancient count), yet line 77 inspects chap (Chaplain count) for pluralisation. This shall produce incorrect grammar when multiple Ancients are selected.

🔧 Proposed correction
     if (champ>0){
         selecting_dudes+=$"{champ} {_roles[eROLE.Ancient]}";
-        if (chap>1) then selecting_dudes+="s";
+        if (champ>1) then selecting_dudes+="s";
         selecting_dudes+=", ";
     }
🤖 Prompt for AI Agents
In objects/obj_controller/Alarm_6.gml around lines 75 to 79, the pluralisation
check uses the wrong variable (`chap`) when appending an "s" for Ancients;
change the conditional to test `champ>1` (the Ancient count) so the string
correctly becomes plural when multiple Ancients are selected, and keep the rest
of the concatenation logic as-is.

Comment on lines 135 to 139
if (assa>0){
selecting_dudes+=string(assa)+" "+string(obj_ini.role[100][eROLE.Assault]);
selecting_dudes+=string(assa)+" "+string(_roles[eROLE.Assault]);
if (sgt>1) then selecting_dudes+="s";
selecting_dudes+=", ";
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Logic corruption in Assault pluralisation, Tech-Priest.

The Machine Spirit perceives another transcription error. The block assembles text for assa (Assault count), yet line 137 inspects sgt (Sergeant count) for pluralisation.

🔧 Proposed correction
     if (assa>0){
         selecting_dudes+=string(assa)+" "+string(_roles[eROLE.Assault]);
-        if (sgt>1) then selecting_dudes+="s";
+        if (assa>1) then selecting_dudes+="s";
         selecting_dudes+=", ";
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (assa>0){
selecting_dudes+=string(assa)+" "+string(obj_ini.role[100][eROLE.Assault]);
selecting_dudes+=string(assa)+" "+string(_roles[eROLE.Assault]);
if (sgt>1) then selecting_dudes+="s";
selecting_dudes+=", ";
}
if (assa>0){
selecting_dudes+=string(assa)+" "+string(_roles[eROLE.Assault]);
if (assa>1) then selecting_dudes+="s";
selecting_dudes+=", ";
}
🤖 Prompt for AI Agents
In objects/obj_controller/Alarm_6.gml around lines 135 to 139, the pluralisation
check incorrectly tests `sgt` when building the Assault text fragment; change
the conditional to test `assa` (e.g., if (assa>1) then ...) so the "s" is added
based on the Assault count, and keep the rest of the string assembly unchanged.

Comment on lines 182 to 189
if (temp<200) and (sgts>0){
if (techmarines=1) then p2+=string(techmarines)+" "+string(obj_ini.role[100][18])+", ";
if (techmarines>1) then p2+=string(techmarines)+" "+string(obj_ini.role[100][18])+", ";
if (techmarines=1) then p2+=string(techmarines)+" "+string(_roles[18])+", ";
if (techmarines>1) then p2+=string(techmarines)+" "+string(_roles[18])+", ";
}
if (temp<200) and (vet_sgts>0){
if (techmarines=1) then p2+=string(techmarines)+" "+string(obj_ini.role[100][19])+", ";
if (techmarines>1) then p2+=string(techmarines)+" "+string(obj_ini.role[100][19])+", ";
if (techmarines=1) then p2+=string(techmarines)+" "+string(_roles[19])+", ";
if (techmarines>1) then p2+=string(techmarines)+" "+string(_roles[19])+", ";
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

CRITICAL LOGIC CORRUPTION DETECTED — Variable mismatch in Sergeant role display, Tech-Priest.

The Machine Spirit perceives a grievous transcription error. The outer conditions inspect sgts and vet_sgts, yet the inner logic references techmarines for both the count comparison and the displayed value. This heresy shall produce erroneous battle narrative output.

🔧 Proposed sanctification of the code-runes
 if (temp<200) and (sgts>0){
-    if (techmarines=1) then p2+=string(techmarines)+" "+string(_roles[18])+", ";
-    if (techmarines>1) then p2+=string(techmarines)+" "+string(_roles[18])+", ";
+    if (sgts=1) then p2+=string(sgts)+" "+string(_roles[18])+", ";
+    if (sgts>1) then p2+=string(sgts)+" "+string(_roles[18])+", ";
 }
 if (temp<200) and (vet_sgts>0){
-    if (techmarines=1) then p2+=string(techmarines)+" "+string(_roles[19])+", ";
-    if (techmarines>1) then p2+=string(techmarines)+" "+string(_roles[19])+", ";
+    if (vet_sgts=1) then p2+=string(vet_sgts)+" "+string(_roles[19])+", ";
+    if (vet_sgts>1) then p2+=string(vet_sgts)+" "+string(_roles[19])+", ";
 }
🤖 Prompt for AI Agents
In objects/obj_ncombat/Alarm_1.gml around lines 182 to 189, the inner
conditionals mistakenly reference techmarines instead of the sergeant counters;
replace occurrences of techmarines with sgts in the first block and with
vet_sgts in the second block, and use the correct equality/comparison operators
for the singular (== 1) and plural (> 1) checks, appending the corresponding
sgts/vet_sgts value with the appropriate _roles index so the displayed counts
and role names match the outer conditions.

Comment on lines +27 to +31
function draw_circle_with_outline_width(xx,yy,r,w){
for (var i=0.0;i<w;i+=0.1){
draw_circle(xx,yy,r+i,1);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

A new rendering rite has been inscribed, Tech-Priest.

The draw_circle_with_outline_width function manifests outline effects through iterative circle rendering. The machine spirits observe:

  • The 0.1 increment creates 10×w draw calls per invocation. For substantial width values, this may burden the rendering pipeline.
  • No documentation enlightens future Tech-Priests on the function's sacred purpose or parameter meanings.
  • The function assumes external configuration of draw colour and alpha state.
⚙️ Proposed improvements
+/// @desc Draws a circle with an outline of specified width by rendering concentric circles
+/// @param {real} xx - X coordinate of circle centre
+/// @param {real} yy - Y coordinate of circle centre  
+/// @param {real} r - Inner radius
+/// @param {real} w - Outline width
 function draw_circle_with_outline_width(xx,yy,r,w){
 	for (var i=0.0;i<w;i+=0.1){
 		draw_circle(xx,yy,r+i,1);
 	}
 }

Consider documenting the performance implications when width exceeds modest values. The rendering spirits favour fewer, bolder strokes over many whispers.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function draw_circle_with_outline_width(xx,yy,r,w){
for (var i=0.0;i<w;i+=0.1){
draw_circle(xx,yy,r+i,1);
}
}
/// @desc Draws a circle with an outline of specified width by rendering concentric circles
/// @param {real} xx - X coordinate of circle centre
/// @param {real} yy - Y coordinate of circle centre
/// @param {real} r - Inner radius
/// @param {real} w - Outline width
function draw_circle_with_outline_width(xx,yy,r,w){
for (var i=0.0;i<w;i+=0.1){
draw_circle(xx,yy,r+i,1);
}
}
🤖 Prompt for AI Agents
In scripts/action_draw_ellipse/action_draw_ellipse.gml around lines 27-31, the
draw_circle_with_outline_width function uses a 0.1 increment which causes ~10*w
draw calls and can severely hurt performance for large widths; update the
function to (1) document its purpose and parameters at the top (what xx, yy, r,
w mean and that color/alpha must be set externally), (2) clamp/limit w to a
sensible maximum (e.g., max_w) and replace the 0.1 loop step with a coarser
configurable step (or compute iterations = max(1, ceil(w/step))) so you do far
fewer draw calls, and (3) optionally add an extra parameter for step or
maxIterations so callers can request higher fidelity when needed; keep
color/alpha management documented (or explicitly save/restore draw state if you
choose to manage it inside the function).

Comment on lines +27 to +30
function instance_at_location(xx,yy,obj_type){
var _nearest = instance_nearest(xx, yy, obj_type);
return (_nearest.x == xx && _nearest.y == yy) ? _nearest : noone;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Warning: Null instance access may corrupt the Machine Spirit.

Tech-Priest, should no instances of obj_type exist within the materium, instance_nearest shall return noone. Accessing noone.x invokes undefined behaviour—a heresy most dire.

🔎 Proposed sanctification with null guard
 function instance_at_location(xx,yy,obj_type){
 	var _nearest = instance_nearest(xx, yy, obj_type);
+	if (_nearest == noone) return noone;
 	return (_nearest.x == xx && _nearest.y == yy) ? _nearest : noone;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function instance_at_location(xx,yy,obj_type){
var _nearest = instance_nearest(xx, yy, obj_type);
return (_nearest.x == xx && _nearest.y == yy) ? _nearest : noone;
}
function instance_at_location(xx,yy,obj_type){
var _nearest = instance_nearest(xx, yy, obj_type);
if (_nearest == noone) return noone;
return (_nearest.x == xx && _nearest.y == yy) ? _nearest : noone;
}
🤖 Prompt for AI Agents
In scripts/instance_create/instance_create.gml around lines 27-30, the code
dereferences a possibly null instance by accessing _nearest.x/_nearest.y without
checking for noone; change the logic to first check if _nearest == noone and
immediately return noone if so, otherwise compare _nearest.x and _nearest.y with
xx/yy and return _nearest or noone accordingly to avoid undefined behavior.

if (_conditions.end_loop){
break;
}
_unit=fetch_unit([com,i]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistent variable naming within loop, Tech-Priest.

Line 13 declares unit but line 47 assigns to _unit. This creates an implicit global variable rather than using the declared local.

🔎 Harmonised variable naming
-			_unit=fetch_unit([com,i]);
+			unit=fetch_unit([com,i]);

-	        if (_conditions.evaluate(_unit)){
-	        	array_push(_units, _unit);
+	        if (_conditions.evaluate(unit)){
+	        	array_push(_units, unit);
 	        }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.gml
around line 47, the loop assigns to _unit while the local variable was declared
as unit earlier, causing an implicit global; change the assignment to use the
declared local variable name (unit = fetch_unit([com,i])) or, if the underscore
name is intended, update the declaration to match (_unit) and ensure it is
declared local with var/let at its declaration site so no implicit globals are
created.

var _add = true;
if (group!="all"){
var _group = group;
if (group_is_array){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Variable identifier mismatch detected, Tech-Priest.

The condition references group_is_array but the variable established on line 69 is group_is_complex. This shall evaluate as undefined.

🔎 Corrected identifier
-		if (group_is_array){
+		if (group_is_complex){
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (group_is_array){
if (group_is_complex){
🤖 Prompt for AI Agents
In
scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.gml
around line 119, the if condition uses the undefined identifier "group_is_array"
while the flag was declared as "group_is_complex" on line 69; update the
condition to use the correct variable name (change "group_is_array" to
"group_is_complex") or, if the intended semantics require an "array" flag,
rename the declaration at line 69 to "group_is_array" so both sites match;
ensure the identifier is consistent across the file.

Comment on lines +208 to +235
static has_role = function(role){
for (var i=0;i<array_length(units);i++){
if (units.role() == role){
return true;
}
}

return false;
}

static has_base_group = function(group){
for (var i=0;i<array_length(units);i++){
if (units.base_group == group){
return true;
}
}

return false;
}

static has_allegiance = function(allegiance){
for (var i=0;i<array_length(units);i++){
if (units.allegiance == allegiance){
return true;
}
}
return false;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Array element access error shall cause logic failure, Tech-Priest.

The machine spirit perceives that units is an array, yet it is accessed directly as an object on lines 210, 220, and 230. The iterator variable units[i] must be invoked.

🔎 Corrected array traversal
 	static has_role = function(role){
 		for (var i=0;i<array_length(units);i++){
-			if (units.role() == role){
+			if (units[i].role() == role){
 				return true;
 			}
 		}

 		return false;
 	}

 	static has_base_group = function(group){
 		for (var i=0;i<array_length(units);i++){
-			if (units.base_group == group){
+			if (units[i].base_group == group){
 				return true;
 			}
 		}

 		return false;		
 	}

 	static has_allegiance = function(allegiance){
 		for (var i=0;i<array_length(units);i++){
-			if (units.allegiance == allegiance){
+			if (units[i].allegiance == allegiance){
 				return true;
 			}
 		}
 		return false;		
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static has_role = function(role){
for (var i=0;i<array_length(units);i++){
if (units.role() == role){
return true;
}
}
return false;
}
static has_base_group = function(group){
for (var i=0;i<array_length(units);i++){
if (units.base_group == group){
return true;
}
}
return false;
}
static has_allegiance = function(allegiance){
for (var i=0;i<array_length(units);i++){
if (units.allegiance == allegiance){
return true;
}
}
return false;
}
static has_role = function(role){
for (var i=0;i<array_length(units);i++){
if (units[i].role() == role){
return true;
}
}
return false;
}
static has_base_group = function(group){
for (var i=0;i<array_length(units);i++){
if (units[i].base_group == group){
return true;
}
}
return false;
}
static has_allegiance = function(allegiance){
for (var i=0;i<array_length(units);i++){
if (units[i].allegiance == allegiance){
return true;
}
}
return false;
}
🤖 Prompt for AI Agents
In
scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.gml
around lines 208 to 235, the code iterates over the units array but accesses
properties/methods directly on units instead of the current element; change each
access to use the loop variable element (units[i]) — replace units.role() with
units[i].role(), units.base_group with units[i].base_group, and units.allegiance
with units[i].allegiance so the checks operate on the current array element.

return match;
}

function collect_by_religeon(religion, sub_cult="", location=""){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typographical error in function nomenclature, Tech-Priest.

The function collect_by_religeon contains a misspelling. The correct form is collect_by_religion. This may impede discoverability.

🔎 Corrected nomenclature
-function collect_by_religeon(religion, sub_cult="", location=""){
+function collect_by_religion(religion, sub_cult="", location=""){
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function collect_by_religeon(religion, sub_cult="", location=""){
function collect_by_religion(religion, sub_cult="", location=""){
🤖 Prompt for AI Agents
In
scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.gml
around line 296, the function name is misspelled as collect_by_religeon; rename
the function declaration to collect_by_religion and update every reference/call
site to the new name, keeping the same parameters and body intact, and adjust
any comments or documentation that mention the old name so all usages match the
corrected identifier.

if (unit.name()=="")then continue;
if (unit.religion == religion){
if (sub_cult!=""){
if (unit.religion_sub_cult != "sub_cult"){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

String literal comparison instead of variable reference, Tech-Priest.

Line 305 compares against the literal string "sub_cult" rather than the sub_cult parameter variable. This shall always evaluate false when a sub_cult is provided.

🔎 Corrected comparison
-        		if (unit.religion_sub_cult != "sub_cult"){
+        		if (unit.religion_sub_cult != sub_cult){
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (unit.religion_sub_cult != "sub_cult"){
if (unit.religion_sub_cult != sub_cult){
🤖 Prompt for AI Agents
In
scripts/scr_UnitGroup_and_group_selection/scr_UnitGroup_and_group_selection.gml
around line 305, the code is comparing unit.religion_sub_cult to the literal
string "sub_cult" which is wrong; change the comparison to use the variable
sub_cult (no quotes) so it reads unit.religion_sub_cult != sub_cult, ensuring
you reference the parameter/variable rather than the literal; if necessary
ensure sub_cult is in scope and handle nil/undefined values consistently (e.g.,
use explicit checks) before comparing.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review continued from previous batch...

Comment on lines +56 to +57
last_turn_check = 0
last_turn_image_check = -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Duplicate initialization detected.

Tech-Priest, last_turn_check is initialized twice—at line 24 and again at line 56. This redundancy pollutes the sacred code. Remove the duplicate to maintain purity.

🔎 Proposed purification
-last_turn_check = 0
 last_turn_image_check = -1;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
last_turn_check = 0
last_turn_image_check = -1;
last_turn_image_check = -1;
🤖 Prompt for AI Agents
In objects/obj_en_fleet/Create_0.gml around lines 56 to 57, there is a duplicate
initialization of last_turn_check (it was already set at line 24); remove the
redundant assignment (the lines "last_turn_check = 0" and the accompanying
"last_turn_image_check = -1;" if that one is also duplicated) at lines 56-57 so
the variable is only initialized once (keep the original initialization at line
24), preserving surrounding formatting and semicolons.

Comment on lines +169 to +179
if (struct_exists(save_data, "events")){
for (var i=0;i<array_length(save_data.events);i++){
var _saved_event = save_data.events[i];
var _event = new FleetEvent();
with (_event){
move_data_to_current_scope(_saved_event);
}
array_push(events, _event);
}

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

FleetEvent construction without required data detected.

Tech-Priest, the invocation at line 172 creates new FleetEvent() without the expected _event_data argument. The constructor at scr_fleet_events.gml line 10 sets self.fleetevent_data = _event_data, which will be undefined when called this way.

While move_data_to_current_scope at line 174 may populate the struct, fleetevent_data will remain as the original undefined value. If any code references fleetevent_data, corruption will occur.

🔎 Proposed sanctification
-            var _event = new FleetEvent();
-            with (_event){
-                move_data_to_current_scope(_saved_event);
-            }
+            var _event = new FleetEvent(_saved_event);
+            _event.load_json_data(_saved_event);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In objects/obj_en_fleet/Create_0.gml around lines 169-179, the code calls new
FleetEvent() without supplying the required _event_data so fleetevent_data
remains undefined; fix this by passing the saved struct into the constructor
(e.g., new FleetEvent(_saved_event)) so fleetevent_data is initialized
correctly, and you can keep or remove the subsequent move_data_to_current_scope
call as needed (if you keep it, ensure it does not rely on fleetevent_data being
set elsewhere).

Comment on lines 67 to +75
switch(owner){
case eFACTION.Ork:
var _has_warboss =false;
var _has_warboss =false;
if (fleet_has_cargo("ork_warboss")){
draw_icon = true;
_has_warboss = true;
}
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Variable scope anomaly detected.

Tech-Priest, _has_warboss is declared at line 69 within the case eFACTION.Ork block, yet it is accessed at line 159 in a separate switch statement that only executes when owner = eFACTION.Ork. While GML's permissive nature prevents catastrophic failure, explicit initialization outside the switch would strengthen the code's fortifications.

🔎 Proposed strengthening
 switch(owner){
+    var _has_warboss = false;
     case eFACTION.Ork:
-        var _has_warboss =false;
           if (fleet_has_cargo("ork_warboss")){

Also applies to: 157-163

🤖 Prompt for AI Agents
In objects/obj_en_fleet/Draw_0.gml around lines 67-75 (and similarly for
157-163), the local variable _has_warboss is declared inside the Ork case and
later read elsewhere, risking undefined state; move the declaration and
initialization (var _has_warboss = false) to before the switch so it is in scope
and defaults to false, then inside the Ork case set _has_warboss = true when
cargo is present and remove the inner var keyword so the later switch can
reliably read the variable.

Comment on lines +194 to +195
var _sprite = ds_map_find_value(global.en_fleet_sprites, uid)
draw_sprite_ext(_sprite, 0, _scale_x_pos-(24*scale) , _scale_y_pos-(24*scale), scale, scale, 1, c_white, 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Potential undefined sprite access.

Tech-Priest, the sprite retrieval at line 194 lacks a defensive check. If the uid is absent from global.en_fleet_sprites (due to race conditions or initialization failures), _sprite will be undefined, and draw_sprite_ext will fail.

Consider adding a guard:

🔎 Proposed fortification
 var _sprite = ds_map_find_value(global.en_fleet_sprites, uid)
+if (!sprite_exists(_sprite)){
+    exit;
+}
 draw_sprite_ext(_sprite, 0,  _scale_x_pos-(24*scale) , _scale_y_pos-(24*scale), scale, scale, 1, c_white, 1);
🤖 Prompt for AI Agents
In objects/obj_en_fleet/Draw_0.gml around lines 194-195, the code reads a sprite
with ds_map_find_value(global.en_fleet_sprites, uid) and immediately calls
draw_sprite_ext, which can crash if the map lookup returns undefined/noone; add
a defensive check before drawing: verify the map contains the uid (ds_map_exists
or check _sprite != undefined/noone/-1 depending on your engine version) and
only call draw_sprite_ext when the sprite is valid, otherwise skip drawing or
use a known fallback sprite and optionally log a warning.

Comment on lines +111 to 114
//TODO bottle these into a constructor for re-use
draw_sprite_ext(spr_servo_left_arm, 0,27+_screen_width,165+_screen_height/3, 2, 2, 0, c_white, 1);
draw_sprite_ext(spr_servo_right_arm, 0,27,165+_screen_height/3, 2, 2, 0, c_white, 1);
draw_sprite_ext(spr_servo_skull_head, 0,27+_screen_width/2,165, 2, 2, 0, c_white, 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

TODO detected in the sacred manuscripts.

Tech-Priest, the Machine Spirit has noted this TODO at line 111 regarding bottling servo-skull sprites into a constructor. Shall this cogitation-task be enshrined in a GitHub issue for the Cult Mechanicus to address in due time?

🤖 Prompt for AI Agents
In objects/obj_star_select/Draw_64.gml around lines 111 to 114, there are three
repeated draw_sprite_ext calls with similar parameters and a TODO to "bottle
these into a constructor"; replace the duplicated logic by creating a reusable
function (e.g., draw_servo_sprite or draw_sprite_scaled) that accepts sprite id,
image_index, x_offset, y_offset, scale_x, scale_y, rotation, color, alpha and
call it for each servo-skull position; update the three call sites to invoke
that function with the appropriate offsets (27+_screen_width / 27 /
27+_screen_width/2 and their y values) so the drawing code is centralized and
easy to reuse.

Comment on lines +1517 to +1635
// increasing necrons
if (array_length(features) != 0) {
var has_awake_tomb = false,
nfleet = 0;
if (awake_tomb_world(features) == 1) {
has_awake_tomb = true;
}
if (has_awake_tomb) {
if (planet_forces[eFACTION.Necrons] < 3) {
planet_forces[eFACTION.Necrons] += 2;
} else if (planet_forces[eFACTION.Necrons] < 6) {
planet_forces[eFACTION.Necrons] += 1;
}
}
if (sabotage_force && irandom(2) < 2) {
planet_forces[eFACTION.Necrons]--;
scr_event_log("green", $"sabotage force on {name()} disrupts necron forces", name);
}

if (has_awake_tomb) {
// Necron fleets, woooo
//necrons kill populatin
if ((population > 0) && (player_forces + pdf + guardsmen + planet_forces[eFACTION.Tyranids] == 0)) {
population = population * 0.75;
if ((large_population == 0) && (population <= 5000)) {
population = 0;
}
}

var fleet_spawn_chance = roll_dice_chapter(1, 100, "high");
onceh = 0;

if (fleet_spawn_chance <= 15) {
if (system.present_fleet[eFACTION.Necrons] > 0) {
//if necron fleet
necron_fleet = instance_nearest(x, y, obj_en_fleet);

if (necron_fleet.owner == eFACTION.Necrons) {
if (necron_fleet.escort_number < necron_fleet.capital_number * 1.5) {
necron_fleet.escort_number += 2;
} else if (necron_fleet.frigate_number < necron_fleet.capital_number * 3) {
necron_fleet.frigate_number += 1;
} else {
necron_fleet.capital_number += 1;
}
}
} else if (system.present_fleet[eFACTION.Necrons] == 0) {
necron_fleet = instance_create(x, y, obj_en_fleet);
necron_fleet.owner = eFACTION.Necrons;
necron_fleet.capital_number = 1;
necron_fleet.sprite_index = spr_fleet_necron;
necron_fleet.image_speed = 0;
necron_fleet.image_index = 1;
system.present_fleet[eFACTION.Necrons] += 1;
}
var enemy_fleets = 0;
with(necron_fleet) {
if (owner == eFACTION.Necrons) {
var ii = 0;
ii += capital_number;
ii += round((frigate_number / 2));
ii += round((escort_number / 4));
if (ii <= 1) {
ii = 1;
} // image_index=max(8,round(ii));

if ((ii >= 7) && (capital_number > 1)) {
for (var fleet_n = 1; fleet_n <= 10; fleet_n++) {
if (orbiting.present_fleet[fleet_n] > 0) {
enemy_fleets++;
}
}
}
}
}
if (enemy_fleets > 0) {
var necron_fleet2;
necron_fleet2 = instance_create(x, y, obj_en_fleet);
necron_fleet2.owner = eFACTION.Necrons;
necron_fleet2.sprite_index = spr_fleet_necron;
// necron_fleet2.image_index=0;
necron_fleet.image_speed = 0;
necron_fleet2.capital_number = 1;
necron_fleet2.frigate_number = round(necron_fleet.frigate_number / 2);
necron_fleet2.escort_number = round(necron_fleet.escort_number / 2);
system.present_fleet[eFACTION.Necrons] += 1;

necron_fleet.capital_number -= 1;
necron_fleet.frigate_number -= necron_fleet2.frigate_number;
necron_fleet.escort_number -= necron_fleet2.escort_number;
var nearest_planet_coords = [0, 0];
var found_near_planet = false;
with(obj_star) {
if (present_fleet[eFACTION.Necrons] == 0) {
if (!array_contains(p_type, "Dead")) {
for (var plan = 1; plan <= planets; plan++) {
if (p_owner[plan] <= 5) {
found_near_planet = true;
nearest_planet_coords = [x, y];
break;
}
}
}
}
}

if (found_near_planet) {
var tgt1, tgt2;

necron_fleet2.action_x = nearest_planet_coords[0];
necron_fleet2.action_y = nearest_planet_coords[1];
with (necron_fleet2){
set_fleet_movement();
}
}
}
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider extraction of Necron awakening logic, Tech-Priest.

The Necron tomb world awakening and fleet manifestation sequence (lines 1517-1635) comprises 118 lines within the broader end-of-turn ritual. The machine spirit suggests consecrating this as a separate static method end_turn_necron_awakening to reduce cognitive burden and align with the pattern established by other faction-specific ceremonies.

🤖 Prompt for AI Agents
In scripts/scr_PlanetData/scr_PlanetData.gml around lines 1517-1635, the
118-line Necron tomb world awakening and fleet-spawn logic should be extracted
into a new static function end_turn_necron_awakening to reduce code size and
mirror other faction handlers; move all logic inside those lines into that
function, determine and pass only the needed inputs (e.g., self/planet context,
features, name, x, y, population, large_population, planet_forces,
player_forces, pdf, guardsmen, sabotage_force, system reference, etc.), have the
function mutate the planet/system objects or return any changed primitives
(population, planet_forces entries, system.present_fleet counts) so existing
state updates remain identical, replace the original block with a single call to
end_turn_necron_awakening(...), and ensure instance_create/with semantics and
local variables (necron_fleet, necron_fleet2, enemy_fleets,
nearest_planet_coords, found_near_planet) are confined to the new function to
avoid scope leaks and preserve behavior and randomness.

// if ((action_score > 100) && (action_score <= 200)) { siz_penalty = 75; }
// if (action_score > 200) { siz_penalty = 125; }

var spec1=0,spec2=0,txt=""; // TODO consider making it a battle with Planetary governor's guards
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

TODO incantation regarding governor guard combat, Tech-Priest.

The notation suggests transforming governor assassination into a proper battle sequence with planetary defenders. Shall the machine spirit inscribe this enhancement into the issue-tracking repository?

Comment on lines +93 to +99
if (!population_large){
pop_after=round(pop_after);
}


var _displayed_population = star.p_large[planet] == 1 ? $"{pop_before} billion" : scr_display_number(floor(pop_before));
var _displayed_killed = star.p_large[planet] == 1 ? $"{kill} billion" : scr_display_number(floor(kill));
txt1 += $"##The world had {_displayed_population} Imperium subjects. {_displayed_killed} were purged over the duration of the bombardment.##Heresy has fallen down to {max(0, heres_after)}%.";
var _displayed_population = display_population();
var _displayed_killed = large_population ? $"{kill} billion" : scr_display_number(floor(kill));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

❓ Verification inconclusive

Script executed:

#!/bin/bash
# Search for both variable names in the scr_purge_world file
rg -n "population_large|large_population" scripts/scr_purge_world/scr_purge_world.gml -A 1 -B 1

Repository: Adeptus-Dominus/ChapterMaster


Repository: Adeptus-Dominus/ChapterMaster
Exit code: 0

stdout:

92-    
93:	    if (!population_large){
94-	    	pop_after=round(pop_after);   
--
98-		var _displayed_population = display_population();
99:		var _displayed_killed = large_population ? $"{kill} billion" : scr_display_number(floor(kill));
100-	    txt1 += $"\n\nThe world had {_displayed_population} Imperium subjects. {_displayed_killed} were purged over the duration of the bombardment.\n\nHeresy has fallen down to {max(0, heres_after)}%.";
--
156-     	
157:     		max_kill = population_large_conversion(12000) *action_score;
158-        
--
163-        
164:	        if (!population_large){
165-	        	pop_after=max(_pop_before-kill,0);
166-	        }
167:	        if (large_population){
168-	        	pop_after=_pop_before;
--
197-            }
198:	        if (!population_large){
199-	        	pop_after=round(pop_after);
--
201-	        
202:	        if (!population_large){
203-	        	txt1+="\n\nThe planet had a population of "+string(scr_display_number(floor(_pop_before)))+" and "+string(scr_display_number(floor(kill)))+" were purged over the duration of the cleansing.\n\nHeresy has fallen down to "+string(max(0,heres_after))+"%.";
--
235-    
236:	        if (!population_large) {
237-	         max_kill=action_score*30;// Population if normal
238-	     	}
239:	        if (large_population) {
240-	         max_kill=0;// Population if large
--
247-        
248:	        if (!population_large) {
249-	         pop_after=max(_pop_before-kill,0);
--
256-        
257:	        if (!population_large) {
258-	         pop_after=round(pop_after);    
--
260-	        
261:	        if (!population_large) {
262-	          txt1+=$"\n\nThe planet had a population of "+string(scr_display_number(floor(_pop_before)))+" and "+string(scr_display_number(floor(kill)))+" die over the duration of the search.\n\nHeresy has fallen to "+string(max(0,heres_after))+"%.";
263-	     	}
264:	        if (large_population) {
265-	          txt1+=$"\n\nThe planet had a population of {_pop_before} billion and {action_score*30} die over the duration of the search.\n\nHeresy has fallen to "+string(max(0,heres_after))+"%.";
--
289-	        }
290:	        if (action_type==DropType.PurgeSelective && !population_large){
291-	        	set_population(pop_after);

Script executed:

#!/bin/bash
# Get the full file to understand context and variable declarations
wc -l scripts/scr_purge_world/scr_purge_world.gml

Repository: Adeptus-Dominus/ChapterMaster


Repository: Adeptus-Dominus/ChapterMaster
Exit code: 0

stdout:

317 scripts/scr_purge_world/scr_purge_world.gml

Script executed:

#!/bin/bash
# Check for variable declarations and initializations
rg -n "^\s*(var|population_large|large_population)\s*=" scripts/scr_purge_world/scr_purge_world.gml

Repository: Adeptus-Dominus/ChapterMaster


Repository: Adeptus-Dominus/ChapterMaster
Exit code: 1


Variable naming inconsistency corrupts the sacred protocols.

Tech-Priest, the machine spirit perceives a troubling duality in the nomenclature of the population threshold. The code employs both population_large (inverted in conditionals at lines 93, 164, 198, 202, 236, 248, 257, 261, 290) and large_population (at lines 99, 167, 239, 264) to represent the same logical concept—a most grievous violation of coherence.

These variables serve complementary conditions within mirrored conditional branches, yet their nomenclature contradicts itself. Unify this nomenclature to a singular truth lest future Tech-Priests stumble upon this contradiction in ritual maintenance.

Also applies to: 164-169, 236-241, 248-266

🤖 Prompt for AI Agents
scripts/scr_purge_world/scr_purge_world.gml lines 93-99, 164-169, 198-202,
236-241, 248-266: the file mixes two names for the same boolean
(population_large vs large_population); pick one canonical name (e.g.,
population_large), then replace all occurrences of the other name in these
ranges and elsewhere in the file to match the chosen name, update any related
conditional checks and displayed variables (e.g., the ternary that sets
_displayed_killed) to use the canonical name, ensure the variable
declaration/initialization uses the same name, and run a project-wide search to
confirm no remaining mismatched references.

Comment on lines +103 to 127
if (current_owner=2 && obj_controller.faction_status[2]!="War"){
if (planet_type="Temperate" || planet_type="Hive" || planet_type="Desert"){
var _disp_hit = -10;
if (star.p_type[planet]="Temperate") then _disp_hit = -5;
if (star.p_type[planet]="Desert") then _disp_hit = -3;
if (planet_type="Temperate"){
_disp_hit = -5;
}
if (planet_type="Desert"){
_disp_hit = -3;
}

scr_audience(eFACTION.Imperium, "bombard_angry", _disp_hit, "", 0, 0);
}
}
}
if (star.p_owner[planet]=3) and (obj_controller.faction_status[3]!="War"){
if (current_owner=3 && obj_controller.faction_status[3]!="War"){

if (star.p_type[planet]="Forge") then _disp_hit =-15;
if (star.p_type[planet]="Ice") then _disp_hit =-7;
if (planet_type="Forge"){
_disp_hit =-15;
}
if (planet_type="Ice"){
_disp_hit =-7;
}
scr_audience(eFACTION.Inquisition, "bombard_angry", _disp_hit, "", 0, 0);

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Assignment-as-comparison detected in conditional blocks.

Tech-Priest, the Machine Spirit observes the use of = rather than == for comparisons at lines 103, 104, 106, 109, 117, 119, 122. While GML tolerates this heresy, it creates ambiguity for future Tech-Adepts maintaining the code. The sacred standard is == for equality checks.

Does this pattern exist throughout the codebase, or should these be standardised?

🤖 Prompt for AI Agents
In scripts/scr_purge_world/scr_purge_world.gml around lines 103 to 127 there are
assignment-into-condition mistakes using = instead of the equality operator ==
(at the lines checking current_owner and planet_type), which causes unintended
assignments; update each conditional to use == for comparisons (e.g.,
current_owner == 2, planet_type == "Temperate", etc.), ensure _disp_hit is
declared/initialized before use where needed, run a project-wide search for
other occurrences of single = inside if/while conditions and standardize them to
==, then test the game logic paths to confirm behavior is unchanged.

Comment on lines 148 to 150
case EVENT.enemy:
if(scr_has_adv("Scavangers")){
events_share[i] += 2;
events_total += 2;
}

break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Empty case block detected in the sacred logic.

Tech-Priest, this case for EVENT.enemy contains naught but void. The Machine Spirit queries: was this emptiness intentional, or has sacred code been excised? If deliberate, a comment would illuminate the purpose for future Tech-Adepts.

🤖 Prompt for AI Agents
In scripts/scr_random_event/scr_random_event.gml around lines 148-150 the case
for EVENT.enemy is an empty block with no comment or handling; either implement
the intended behavior for enemy events (e.g., call the enemy event handler, set
event state, spawn enemies, or update relevant variables) or, if intentionally
left empty, add a concise explanatory comment like "Intentionally no-op: enemies
handled elsewhere" so future readers know this is deliberate. Ensure the chosen
fix follows surrounding code patterns (use existing helper functions or state
changes used by other cases) and preserves switch fallthrough semantics if
applicable.

@EttyKitty EttyKitty changed the title Feat: Multi-part missions and governor profiles feat: Multi-part missions and governor profiles Dec 30, 2025
@EttyKitty EttyKitty marked this pull request as draft December 30, 2025 05:03
@github-actions github-actions bot added the Type: Feature Adds something new label Dec 30, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Jan 6, 2026

This PR is marked as stale, because it has been open for 7 days with no activity.

@github-actions github-actions bot added the Status: Stale No activity for more than a week label Jan 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Sprites Changes to sprites/images or their under-the-hood functionality Size: Warning Status: Stale No activity for more than a week Type: Feature Adds something new

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant